/*-----------------------------------------------------------------------------
	The contents of this file are subject to the Mozilla Public License
	Version 1.1 (the "License"); you may not use this file except in
	compliance with the License.You may obtain a copy of the License at
	http://www.mozilla.org/MPL/MPL-1.1.html
	
	Software distributed under the License is distributed on an "AS IS"
	basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
	License for the specific language governing rights and limitations
	under the License.
	
	The Original Code is Fever Framework code.
	
	The Initial Developer of the Original Code is Romain Ecarnot.
	Portions created by Initial Developer are Copyright (C) 2006
	the Initial Developer. All Rights Reserved.
	
	Contributor(s):
	
	Unless required by applicable law or agreed to in writing, software
	distributed under the License is distributed on an "AS IS" BASIS,
	WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
	See the License for the specific language governing permissions and
	limitations under the License.
-----------------------------------------------------------------------------*/

import fever.data.validators.ValidationResources;
import fever.utils.ArrayUtil;
import fever.utils.MathUtils;

/**
 * Used to generate a stream of pseudorandom numbers, chars or words.
 *
 * @author Romain Ecarnot
 */
class fever.utils.Random
{	
	//-------------------------------------------------------------------------
	// Constants definition
	//-------------------------------------------------------------------------
	
	/** Constant. Defines if char or worf must be in upper case or not. */
	public static var UPPER_TYPE : String = 'upper';
	
	/** Constant. Defines if char or worf must be in lower case or not. */
	public static var LOWER_TYPE : String = 'lower';
	
	/** 
	 * Constant. Defines if char or word can contain upper and lower 
	 * case char.
	 */
	public static var MIXED_TYPE : String = 'mixed';
	
	/** Default password length for {@link #nextPassword()} method. */
	public static var DEFAULT_PASSWORD_LENGTH : Number = 8;
	
	
	//-------------------------------------------------------------------------
	// Public API
	//-------------------------------------------------------------------------
	
	/**
	 * Returns a new random {@code Boolean}.
	 */
	public static function nextBoolean( ) : Boolean
	{
		var float : Number = Math.random();
		return (float < 0.5);
	}
	
	/**
	 * Returns a new random float.
	 * 
	 * @param limit Limit of possible generated number
	 */
	public static function nextFloat( limit : Number ) : Number
	{
		var max : Number = ( limit >= 0 ) ? limit : Number.MAX_VALUE;
		var result : Number = Math.random() * max;
		return result;
	}
	
	/**
	 * Return a new random integer
	 * 
	 * @param limit Limit of possible generated number
	 */
	public static function nextInt( limit : Number ) : Number
	{
		var result : Number = nextFloat( limit );
		return Math.round( result );
	}
	
	/**
	 * Returns a new random char.
	 * 
	 * @param readable Is generation still in human readable chars table
	 * @param type Possible values are :
	 * <ul>
	 *   <li>{@link #UPPER_TYPE}</li>
	 *   <li>{@link #LOWER_TYPE}</li>
	 *   <li>{@link #MIXED_TYPE}</li>
	 * </ul>
	 */
	public static function nextChar( readable : Boolean, type : String ) : String
	{
		var human : Boolean = ( readable == false ) ? false : true;
		
		var min : Number = 97;  
		var max : Number = 122;
		
		if( !human ) 
		{
			min = 0;
			max = 255;
		}
		
		var result : String = String.fromCharCode( MathUtils.random(min, max) );
		switch( type ) 
		{
			case UPPER_TYPE :
				return result.toUpperCase();
			case MIXED_TYPE : 
				return ( nextBoolean() ) ? result : result.toUpperCase();
			default :
				return result;
		}
	}
	
	/**
	 * Returns a new random word.
	 * 
	 * @param limit Max chars in word ( must be > -1 and < 27 )
	 * @param type Possible values are :
	 * <ul>
	 *   <li>{@link #UPPER_TYPE}</li>
	 *   <li>{@link #LOWER_TYPE}</li>
	 *   <li>{@link #MIXED_TYPE}</li>
	 * </ul>
	 */
	public static function nextWord( limit : Number, type : String ) : String
	{
		var result : String = '';
		var l : Number = 26;
		if( limit > -1 && limit < 27) l = limit;
		
		for( var i : Number = 0; i < l; i++ )
		{
			var char : String = nextChar( true, type );
			result += char;
		}
		return result;
	}
	
	/**
	 * Returns a new random generated password.
	 * 
	 * @param useNumber {@code true} to enable number in string ( default is {@code true} )
	 * @param mixCap {@code true} to enable lower and uppercase mix ( either 
	 * just lowercase are used ) ( default is {@code true} )
	 * @param useOther {@code true} to enable special character use ( default is {@code false} )
	 * @param min ( optional )Minimum length for generated password ( default is {@link #DEFAULT_PASSWORD_LENGTH} )
	 * @param max ( optional )Maximum length for generated password
	 * 
	 * @return String password
	 */
	public static function nextPassword( useNumber : Boolean, mixCap : Boolean, useOther : Boolean, min : Number, max : Number ) : String
	{
		useNumber = ( useNumber == false ) ? false : true;
		mixCap = ( mixCap == false ) ? false : true;
		useOther = ( useOther == true ) ? true : false;
		
		if( isNaN( min ) || min <= 0 ) min = DEFAULT_PASSWORD_LENGTH;
		if( isNaN( max ) || max < min ) max = min;
		
		var template :  Array = _createTemplate( useNumber, mixCap, useOther );
		var length : Number = MathUtils.random( min, max, true );
		var result : String = '';
		
		for ( var i : Number = 0; i < length; i++ )
		{
			result += ArrayUtil.getRandomSlot( template )();
		}
		
		return result;
	}
	
	
	//-------------------------------------------------------------------------
	// Private implementation
	//-------------------------------------------------------------------------
	
	private static function _createTemplate( useNumber : Boolean, mixCap : Boolean, useOther : Boolean ) : Array
	{
		var pattern : Array = new Array();
		
		if( useNumber ) pattern.push( _getNumber );
		
		if( mixCap ) pattern.push( _getMix );
		else pattern.push( _getLower );
		
		if( useOther ) pattern.push( _getCustom );
		
		return pattern;
	}
	
	private static function _getNumber() : String
	{
		return String( MathUtils.random( 0, 9, true ) );
	}
	
	private static function _getLower() : String
	{
		return nextChar( true, Random.LOWER_TYPE );	
	}
	
	private static function _getMix() : String
	{
		return nextChar( true, Random.MIXED_TYPE );
	}
	
	private static function _getCustom() : String
	{
		return String( 
			ArrayUtil.getRandomSlot( 
				ValidationResources.getInstance().password_special_chars 
			) 
		);	
	}
	
	private function Random () {}
	
}